package com.apache.ius.plugin;

import com.alibaba.druid.pool.DruidDataSource;
import com.apache.api.manager.ProxyManager;
import com.apache.api.vo.ParamsVo;
import com.apache.api.vo.ResultEntity;
import com.apache.cache.service.impl.LoadCacheFactory;
import com.apache.cache.util.Validator;
import com.apache.client.IUSRequestParams;
import com.apache.database.datasource.ConnctionData;
import com.apache.database.datasource.DynamicDataSource;
import com.apache.database.db.IDao;
import com.apache.database.model.MethodParam;
import com.apache.exception.BusinessException;
import com.apache.ius.IusSqlTools;
import com.apache.ius.able.CacheHelper;
import com.apache.ius.able.ScheduledExecutor;
import com.apache.ius.able.SelectDatasourceCall;
import com.apache.rpc.common.LoadRpcService;
import com.apache.rpc.entity.InterfaceRegister;
import com.apache.rpc.entity.RpcDatasource;
import com.apache.tools.ConfigUtil;
import com.apache.tools.StrUtil;
import com.apache.uct.common.ToolsUtil;
import net.sf.json.JSONObject;
import org.apache.log4j.Logger;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Future;

/**
 * description: IUS数据接口工具类
 *
 * @author dyh 创建时间：2018年08月15日
 */
public class IusPluginUtil {

	private Logger log = Logger.getLogger(getClass());
	private ProxyManager iusProxyManager;
	private IDao iusPubDao;

	private static IusPluginUtil instance;

	private IusPluginUtil() {

	}

	/**
	 * 利用平台查询业务表数据，不带事务（具体返回单条还是多条，以whereMap中拼装的查询条件为准）
	 * @param resultType 返回值类型(list/obj/count)
	 * @param searchObjName 指定要查询的表对象，如s_teUserTest
	 * @param whereMap 拼装查询条件[格式如：对象.w_属性=值/对象.wl_属性=值]，如whereMap.put("teUserTest.w_userSex","F");
	 * @return
	 */
	public ResultEntity select(String resultType, String searchObjName, Map<String, Object> whereMap)
			throws BusinessException {
		ParamsVo vo = new ParamsVo();
		if (whereMap != null && whereMap.size() > 0) {
			vo.setParams(whereMap);
		}
		vo.setKey("iusTransaction");
		vo.setParams("resultType", "objInfo");
		vo.setParams("resultObjType", resultType);
		//拼装参数
		vo.setParams("modelTypes", searchObjName);
		log.info("请求参数：" + vo.getParams());
		ResultEntity res = (ResultEntity) iusProxyManager.doInvoke(vo);
		return res;
	}

	/**
	 * 【跨数据源】利用平台查询业务表数据，不带事务（具体返回单条还是多条，以whereMap中拼装的查询条件为准）
	 * @param datasource 数据源
	 * @param resultType 返回值类型(list/obj/count)
	 * @param searchObjName 指定要查询的表对象，如s_teUserTest
	 * @param whereMap 拼装查询条件[格式如：对象.w_属性=值/对象.wl_属性=值]，如whereMap.put("teUserTest.w_userSex","F");
	 * @return
	 */
	public ResultEntity select(String datasource, String resultType, String searchObjName, Map<String, Object> whereMap)
			throws BusinessException {
		whereMap.put("datasource", datasource);
		whereMap.put("modelTypes", searchObjName);
		whereMap.put("resultObjType", resultType);
		whereMap.put("resultType", "objInfo");
		if (StrUtil.isNull(String.valueOf(whereMap.get("sqlKeyId")))) {
			whereMap.put("sqlKeyId", "sqlKeyId");
		}
		whereMap.put("sysPass", ConfigUtil.getInstance().interfacePass());
		log.info("请求参数：" + whereMap);
		InterfaceRegister register = new InterfaceRegister();
		register.setAddress("127.0.0.1");
		register.setCallType("socket");
		ResultEntity res = (ResultEntity) LoadRpcService.service().doServiceClient(getBeanId(datasource), "dymicSql",
				whereMap, register);
		return res;
	}

	/**
	 * 【调用第三方ius的Service服务端】
	 * @param pageName ius接口参数pageName
	 * @param formName ius接口参数formName
	 * @param paramMap 其他业务参数
	 * @return ResultEntity
	 * @throws BusinessException
	 */
	public ResultEntity sendToIusService(String pageName, String formName, Map<String, Object> paramMap) throws BusinessException {
		ResultEntity entity = new ResultEntity();
		entity.setResult("false");
		entity.setMessage("通信失败");
		log.info("请求接口：sendToIusService ---> pageName="+pageName+",formName="+formName);
		//准备需要第三方系统操作的：ius参数、相关配置的插件
		if(paramMap==null){
			paramMap = new HashMap<String,Object>();
		}
		paramMap.put("sysPass", ConfigUtil.getInstance().interfacePass());
		paramMap.put("resultType", "objInfo");
		paramMap.put("req_pageName",pageName);
		paramMap.put("req_formName",formName);
		try {
			String req_sysEname = ConfigUtil.getInstance().getLocalByKey("config.properties","sysEname");
			paramMap.put("req_sysEname",req_sysEname);
		} catch (Exception e) {
			e.printStackTrace();
		}
		String pkey = formName + "_" + pageName;
		Map mapCache = (Map) CacheHelper.getInstance().getIusParamCache(pkey);
		if (ToolsUtil.isEmpty(mapCache)) {
			throw new BusinessException("缓存数据中未找到key->"+pkey);
		}
		String datasource = String.valueOf(mapCache.get("sysName"));
		Map params = IUSRequestParams.analyzeParams(mapCache, paramMap);
		paramMap.putAll(params);
		log.info("请求参数：" + paramMap);
		InterfaceRegister register = new InterfaceRegister();
		register.setAddress("127.0.0.1");
		register.setCallType("socket");
		entity = LoadRpcService.service().doServiceClient(getBeanId(datasource), "dymicSql", paramMap, register);
		log.info("返回结果：" + JSONObject.fromObject(entity));
		return entity;
	}

	/**
	 * 获取给定sql的数据信息
	 * @param sql 待执行sql
	 * @param pageIndex 当前页（查分页时用，不分页为0）
	 * @param pageSize 记录数（查分页时用，不分页为0）
	 * @return List<DataMap>
	 */
	public Object select(String sql, int pageIndex, int pageSize) throws BusinessException {
		log.info("执行自定义SQL：" + sql);
		log.info("分页查询参数：pageIndex=" + pageIndex + ",pageSize=" + pageSize);
		MethodParam params = new MethodParam("ByObjInfo", "", "", IusSqlTools.SPANCENAME);
		params.setParams("dyncSql", sql);
		params.setResultCache(false);
		if (pageSize > 0 && pageIndex > 0) {
			params.setPageIndex(pageIndex);
			params.setPageSize(pageSize);
			return iusPubDao.pageSelect(params);
		}
		return iusPubDao.select(params);
	}

	/**
	 * 【跨数据源】查询自定义sql的数据信息
	 * @param sql 待执行sql
	 * @param datasource 指定的数据源
	 * @param pageIndex 当前页（查分页时用，不分页为0）
	 * @param pageSize 记录数（查分页时用，不分页为0）
	 * @return List<DataMap>
	 */
	public Object select(String datasource, String sql, int pageIndex, int pageSize) throws BusinessException {
		log.info("通过数据源[" + datasource + "]执行自定义SQL：" + sql);
		log.info("分页查询参数：pageIndex=" + pageIndex + ",pageSize=" + pageSize);
		SelectDatasourceCall call = new SelectDatasourceCall(sql, datasource, pageIndex, pageSize);
		try {
			Future<Object> future1 = ScheduledExecutor.instance().submitObj(call);
			Object obj = future1.get();
			return obj;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 利用平台处理业务表数据（提交，修改，删除），带事务
	 * @param saveObjName 指定要处理的表对象，如i_teUserTest/u_teUserTest/d_teUserTest
	 * @param paramsMap 相应操作的参数、操作的条件，不能为空;
	 * @param isTransaction 是否开事务
	 * @return
	 */
	public ResultEntity saveInvoke(String saveObjName, Map<String, Object> paramsMap, boolean isTransaction)
			throws BusinessException {
		ParamsVo vo = new ParamsVo();
		if (paramsMap != null && paramsMap.size() > 0) {
			vo.setParams(paramsMap);
		}
		vo.setKey("iusTransaction");
		vo.setParams("resultType", "processSql");
		//拼装参数
		vo.setParams("modelTypes", saveObjName);
		log.info("请求参数：" + vo.getParams());
		ResultEntity res = null;
		if (isTransaction) {
			res = (ResultEntity) iusProxyManager.saveInvoke(vo);
		} else {
			res = (ResultEntity) iusProxyManager.doInvoke(vo);
		}
		return res;
	}

	/**
	 * 执行自定义的sql保存、修改或删除数信息(不带事务)
	 * @param sql 待执行sql
	 * @return
	 */
	public boolean saveInvoke(String sql) throws BusinessException {
		MethodParam params = new MethodParam("ByDymicSql", "", "", IusSqlTools.SPANCENAME);
		params.setParams("execSql", sql);
		return iusPubDao.edit(params);
	}

	/**
	 * 【跨数据源】执行自定义的sql保存、修改或删除数信息
	 * @param datasource 指定的数据源
	 * @param sql 待执行sql
	 * @return
	 */
	public boolean saveInvoke(String datasource, String sql) throws BusinessException {
		DruidDataSource dbDao = null;
		datasource = StrUtil.doNull(datasource, DynamicDataSource.getInstance().getDefaultDataSourceKey());
		if (!DynamicDataSource.getInstance().checkDataSource(datasource)) {
			Object obj = LoadCacheFactory.getInstance().getCacheManager("")
					.getCacheObjectByKey("rpc_datasource_" + datasource);
			if (null == obj) {
				throw new BusinessException("获取数据源[" + datasource + "]失败！");
			}
			RpcDatasource rds = (RpcDatasource) obj;
			if (!DynamicDataSource.getInstance().addDataSource(rds.getSysEname(), rds.getDriverClassName(),
					rds.getJdbcUrl(), rds.getJdbcUsername(), rds.getJdbcPassword())) {
				throw new BusinessException("连接数据源[" + datasource + "]失败！");
			}
		}
		log.info("通过数据源[" + datasource + "]执行自定义SQL：" + sql);
		dbDao = DynamicDataSource.getInstance().getDataSource(datasource);
		Connection con = null;
		try {
			con = dbDao.getConnection();
		} catch (SQLException e) {
			DynamicDataSource.getInstance().removeDataSource(datasource);
			log.error("执行sql=" + sql + ";执行失败:" + e.getMessage());
			return false;
		}
		return ConnctionData.getInstance().execute(con, sql);
	}

	public boolean saveBatchInvoke(String datasource, String sql) throws BusinessException {
		DruidDataSource dbDao = null;
		datasource = StrUtil.doNull(datasource, DynamicDataSource.getInstance().getDefaultDataSourceKey());
		if (!DynamicDataSource.getInstance().checkDataSource(datasource)) {
			Object obj = LoadCacheFactory.getInstance().getCacheManager("")
					.getCacheObjectByKey("rpc_datasource_" + datasource);
			if (null == obj) {
				throw new BusinessException("获取数据源[" + datasource + "]失败！");
			}
			RpcDatasource rds = (RpcDatasource) obj;
			if (!DynamicDataSource.getInstance().addDataSource(rds.getSysEname(), rds.getDriverClassName(),
					rds.getJdbcUrl(), rds.getJdbcUsername(), rds.getJdbcPassword())) {
				throw new BusinessException("连接数据源[" + datasource + "]失败！");
			}
		}
		log.info("通过数据源[" + datasource + "]执行自定义SQL：" + sql);
		dbDao = DynamicDataSource.getInstance().getDataSource(datasource);
		Connection con = null;
		try {
			con = dbDao.getConnection();
		} catch (SQLException e) {
			DynamicDataSource.getInstance().removeDataSource(datasource);
			log.error("执行sql=" + sql + ";执行失败:" + e.getMessage());
			return false;
		}
		List<String> sqls = Arrays.asList(sql.split(";"));
		return ConnctionData.getInstance().execute(con, sqls);
	}

	/**
	 * 【跨数据源】RPC保存操作，利用平台处理业务表数据（提交，修改，删除），带事务
	 * @param datasource 指定系统所属数据源，如平台的plateform
	 * @param saveObjName 指定要处理的表对象，如i_teUserTest/u_teUserTest/d_teUserTest
	 * @param paramsMap 相应操作的参数、操作的条件，不能为空;
	 * @return
	 */
	public ResultEntity saveInvoke(String datasource, String saveObjName, Map<String, Object> paramsMap)
			throws BusinessException {
		paramsMap.put("datasource", datasource);
		paramsMap.put("modelTypes", saveObjName);
		paramsMap.put("resultType", "processSql");
		if (StrUtil.isNull(String.valueOf(paramsMap.get("sqlKeyId")))) {
			paramsMap.put("sqlKeyId", "sqlKeyId");
		}
		paramsMap.put("sysPass", ConfigUtil.getInstance().interfacePass());
		log.info("请求参数：" + paramsMap);
		InterfaceRegister register = new InterfaceRegister();
		register.setAddress("127.0.0.1");
		register.setCallType("socket");
		return LoadRpcService.service().doServiceClient(getBeanId(datasource), "dymicSql", paramsMap, register);
	}

	public void init() {
		instance = this;
	}

	public static IusPluginUtil getInstance() {
		return instance;
	}

	public void setIusProxyManager(ProxyManager iusProxyManager) {
		this.iusProxyManager = iusProxyManager;
	}

	public void setIusPubDao(IDao iusPubDao) {
		this.iusPubDao = iusPubDao;
	}

	private String getBeanId(String datasourceName) {
		String beanId = "iusService";
		if (StrUtil.isNotNull(datasourceName)) {
			if ("cms".equals(datasourceName)) {
				beanId = "websiteService";
			} else {
				beanId = datasourceName + "Service";
				if (!isExites(beanId) || "memberService".equals(beanId)) {
					beanId = "iusService";
				}
			}
		}
		return beanId;
	}

	private boolean isExites(String beanId) {
		if (StrUtil.isNull(beanId))
			return false;
		String cacheKey = "interfaceRegister_" + beanId;
		return LoadCacheFactory.getInstance().getCacheManager("").checkCacheObject(cacheKey);
	}
}
